﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace SimpleORM
{
    public class GroupByTranslator : LambdaTranslator
    {
        #region Properties

        public Type ObjectType { get; private set; }
        public List<string> ColumnAliasNames { get; private set; }
        public Dictionary<string, IScriptFactory> GroupByKeys { get; set; }

        #endregion

        #region Ctor

        public GroupByTranslator()
        {
            ColumnAliasNames = new List<string>();
            GroupByKeys = new Dictionary<string, IScriptFactory>();
        }

        #endregion

        #region Methods

        #region Methods - Public

        public override void Translate(Expression expression)
        {
            base.Translate(expression);
            Stack.Push(Result);

            List<IScriptFactory> items = Stack.ToList();
            items.Reverse();
            for (int i = 0; i < items.Count; i++)
                GroupByKeys[ColumnAliasNames[i]] = items[i];

            Result = new SelectObjectContext().BuildSelect(items);
        }

        protected override Expression VisitParameter(ParameterExpression p)
        {
            if (!FromNameDictionary.ContainsKey(p.Type))
                return p;

            ObjectType = p.Type;

            SelectObjectContext e = new SelectObjectContext();
            e.Factory = DataSource.CreateScriptFactory();
            e.Install(ObjectContextDictionary[ObjectType],
                      FromNameDictionary[ObjectType]);

            e.SelectObjectItems.ForEach(item => Stack.Push(item.GetItemName()));
            e.SelectObjectItems.ForEach(item => ColumnAliasNames.Add(item.AliasName));

            return base.VisitParameter(p);
        }

        protected override NewExpression VisitNew(NewExpression n)
        {
            ObjectType = n.Type;
            foreach (var item in n.Members)
                ColumnAliasNames.Add(item.Name);

            return base.VisitNew(n);
        }

        protected override Expression VisitMemberInit(MemberInitExpression init)
        {
            ObjectType = init.NewExpression.Type;
            foreach (var item in init.Bindings)
                ColumnAliasNames.Add(item.Member.Name);

            return base.VisitMemberInit(init);
        }

        protected override Expression VisitMemberAccess(MemberExpression m)
        {
            if (FromNameDictionary.ContainsKey(m.Type))
            {
                ObjectType = m.Type;

                SelectObjectContext e = new SelectObjectContext();
                e.Factory = DataSource.CreateScriptFactory();
                e.Install(ObjectContextDictionary[m.Type],
                          FromNameDictionary[m.Type]);

                e.SelectObjectItems.ForEach(item => Stack.Push(item.GetItemName()));
                e.SelectObjectItems.ForEach(item => ColumnAliasNames.Add(item.AliasName));

                return m;
            }

            if (ObjectType == null)
            {
                ObjectType = m.Type;
                ColumnAliasNames.Add(m.Member.Name);
            }

            return base.VisitMemberAccess(m);
        }

        #endregion

        #endregion
    }
}
